#include "common/data_scene.h"

#include <algorithm>
#include <boost/algorithm/string.hpp>
#include <boost/json.hpp>
#include <chrono>
#include <functional>
#include <opencv2/opencv.hpp>
#include <sstream>

#include "common/file_helper.h"
#include "common/io_helper.h"

DataScene::~DataScene() {
  is_init_ = false;
  is_dispose_ = true;
  if (data_scene_load_task.joinable()) {
    data_scene_load_task.join();
  };
}

void DataScene::Init(std::string const& path) noexcept {
  std::lock_guard<std::mutex> lock(mutex_);
  if (is_init_) return;
  data_path_ = path;

  // start data frame task
  auto load_scene_data_func{std::bind(&DataScene::load_data_scene, this)};
  data_scene_load_task = std::thread(load_scene_data_func);
  is_init_ = true;
}

bool DataScene::WriteMap(std::string const& path, Map const& map,
                         std::string& err) noexcept {
  boost::system::error_code errCode;
  if (!boost::filesystem::exists(path, errCode)) {
    if (!boost::filesystem::create_directories(path, errCode)) {
      err = "create path: " + path + "fail, " + errCode.message();
      return false;
    }
  }
  boost::json::value jv;
  auto& jo = jv.emplace_object();

  boost::json::array jaLaneDivider;
  boost::json::array jaRoadEdge;
  boost::json::array jaRoadMarking;

  // lane divider
  for (uint32_t i = 0; i < map.lane_divider.GetNumberFilled(); i++) {
    auto const& line{map.lane_divider.Get(i)};
    boost::json::object joLine;
    boost::json::array jaPoint;
    // id
    joLine["id"] = line.id;

    if (line.type == LineType::Dashed) {
      joLine["line_type"] = "dashed";
      joLine["color"] = line.color;
    }

    if (line.type == LineType::Solid) {
      joLine["line_type"] = "solid";
      joLine["color"] = line.color;
    }

    // points
    for (uint32_t j = 0; j < line.points.GetNumberFilled(); j++) {
      auto const& point{line.points.Get(j)};
      jaPoint.emplace_back(boost::json::array({point.x, point.y, point.z}));
    }

    joLine["points"] = jaPoint;
    jaLaneDivider.emplace_back(joLine);
  }

  // road edge
  for (uint32_t i = 0; i < map.road_edge.GetNumberFilled(); i++) {
    auto const& line{map.road_edge.Get(i)};
    boost::json::object joLine;
    boost::json::array jaPoint;
    // id
    joLine["id"] = line.id;

    // points
    for (uint32_t j = 0; j < line.points.GetNumberFilled(); j++) {
      auto const& point{line.points.Get(j)};
      jaPoint.emplace_back(boost::json::array({point.x, point.y, point.z}));
    }

    joLine["points"] = jaPoint;
    jaRoadEdge.emplace_back(joLine);
  }

  // road marking
  for (uint32_t i = 0; i < map.road_marking.GetNumberFilled(); i++) {
    auto const& line{map.road_marking.Get(i)};
    boost::json::object joLine;
    boost::json::array jaPolygens;
    boost::json::array jaCategorys;
    // id
    joLine["id"] = line.id;

    // category
    for (size_t k = 0; k < line.categorys.GetNumberFilled(); k++) {
      auto const& category{line.categorys.Get(k)};
      jaCategorys.emplace_back(category);
    }

    joLine["category"] = jaCategorys;

    // polygon
    for (uint32_t j = 0; j < line.polygons.GetNumberFilled(); j++) {
      auto const& polygon{line.polygons.Get(j)};
      jaPolygens.emplace_back(
          boost::json::array({polygon.x, polygon.y, polygon.z}));
    }

    joLine["polygon"] = jaPolygens;

    jaRoadMarking.emplace_back(joLine);
  }

  jo["lane_divider"] = jaLaneDivider;
  jo["road_edge"] = jaRoadEdge;
  jo["road_marking"] = jaRoadMarking;

  auto strJson{boost::json::serialize(jv)};
  auto fileName{std::to_string(map.timestamp) + ".json"};
  auto filePath{boost::filesystem::complete(fileName, path).string()};
  std::unique_ptr<std::ofstream, std::function<void(std::ofstream*)>> foutPtr(
      new std::ofstream(filePath), [&](std::ofstream* p) {
        if (p != nullptr) p->close();
      });
  *foutPtr << strJson;

  return true;
}

bool DataScene::WriteObject(std::string const& path,
                            PerceptionResult const& perception,
                            std::string& err) noexcept {
  boost::system::error_code errCode;
  if (!boost::filesystem::exists(path, errCode)) {
    if (!boost::filesystem::create_directories(path, errCode)) {
      err = "create path: " + path + "fail, " + errCode.message();
      return false;
    }
  }
  boost::json::value jv;
  auto& jo = jv.emplace_array();

  for (uint32_t i = 0; i < perception.dl_boxes.GetNumberFilled(); i++) {
    auto const& obj{perception.dl_boxes.Get(i)};
    boost::json::object joLine;
    boost::json::array jaPoint;
    boost::json::object jaCenter;
    boost::json::object jaSize;
    boost::json::object jaRotation;
    boost::json::object jaVelocity;
    boost::json::object jaAcceleration;

    // id
    joLine["id"] = obj.id;

    joLine["category"] = obj.label;

    joLine["num_lidar_pts"] = 0;

    joLine["num_radar_pts"] = 0;

    // center
    jaCenter["x"] = obj.center.x;
    jaCenter["y"] = obj.center.y;
    jaCenter["z"] = obj.center.z;
    joLine["center"] = jaCenter;

    // size
    jaSize["x"] = obj.length;
    jaSize["y"] = obj.width;
    jaSize["z"] = obj.height;
    joLine["size"] = jaSize;

    // rotation
    jaRotation["x"] = obj.r;
    jaRotation["y"] = 0.0;
    jaRotation["z"] = 0.0;
    joLine["rotation"] = jaRotation;

    // // polygen
    for (uint32_t j = 0; j < obj.polygon.GetNumberFilled(); j++) {
      auto const& polygen{obj.polygon.Get(j)};
      jaPoint.emplace_back(boost::json::array({polygen.x, polygen.y}));
    }

    joLine["polygen"] = jaPoint;

    jaVelocity["x"] = obj.vx;
    jaVelocity["y"] = obj.vy;
    jaVelocity["z"] = 0.0;
    joLine["velocity"] = jaVelocity;

    jaAcceleration["x"] = obj.ax;
    jaAcceleration["y"] = obj.ay;
    jaAcceleration["z"] = 0.0;
    joLine["acceleration"] = jaAcceleration;

    jo.emplace_back(joLine);
  }

  auto strJson{boost::json::serialize(jv)};
  auto fileName{std::to_string(perception.timestamp) + ".json"};
  auto filePath{boost::filesystem::complete(fileName, path).string()};
  std::unique_ptr<std::ofstream, std::function<void(std::ofstream*)>> foutPtr(
      new std::ofstream(filePath), [&](std::ofstream* p) {
        if (p != nullptr) p->close();
      });
  *foutPtr << strJson;

  return true;
}

void DataScene::travel_timestamp_data_file(
    boost::filesystem::path const& path,
    std::vector<boost::filesystem::path>& files) noexcept {
  boost::filesystem::directory_iterator dataIter(path);
  for (auto const& data : dataIter) {
    files.emplace_back(data.path());
  }
  std::sort(
      files.begin(), files.end(),
      [](boost::filesystem::path const& lp, boost::filesystem::path const& rp) {
        auto lt = std::strtoull(lp.filename().stem().c_str(), 0, 0);
        auto rt = std::strtoull(rp.filename().stem().c_str(), 0, 0);
        return lt <= rt;
      });
}

bool DataScene::parse_data_frame_info(boost::filesystem::path const& root_path,
                                      DataFrameInfo& info,
                                      std::string& err) noexcept {
  boost::system::error_code errCode;
  if (!boost::filesystem::exists(root_path, errCode)) {
    err = "file path: " + root_path.string() + "not exist";
    return false;
  }
  boost::filesystem::directory_iterator rootDirIter(root_path);
  for (auto const& sub : rootDirIter) {
    std::vector<boost::filesystem::path> files;
    travel_timestamp_data_file(sub.path(), files);
    info.emplace(sub.path().filename().string(), files);
  }
  return true;
}

bool DataScene::read_lidar_data(
    std::string const& path, std::uint32_t const& feature_number,
    PointCloud<PointXYZIT, kMaxPointNum>& point_cloud,
    std::string& err) noexcept {
  if (!is_file_exist(path)) {
    err = "file: " + path + " does not exist";
    return false;
  }

  if (feature_number < kMinLidarDataFeatureNum) {
    err = "feature number must be at least " +
          std::to_string(kMinLidarDataFeatureNum);
    return false;
  }

  auto binSize{get_binfile_size(path)};
  auto dataNumber{binSize / sizeof(float)};

  // data number is not enough
  if (dataNumber < kMinLidarDataFeatureNum) {
    err = "data number: " + std::to_string(dataNumber) + " is not enough";
    return false;
  }

  char* buf{new char[binSize]};
  read_bin_file(path, buf, binSize);
  float* fbuf = reinterpret_cast<float*>(buf);
  auto pointNumber{dataNumber / feature_number};
  point_cloud.Clear();
  for (auto i{0}; i < pointNumber; i++) {
    if (i < kMaxPointNum) {
      PointXYZIT p{
          .x = fbuf[i * feature_number + 0],
          .y = fbuf[i * feature_number + 1],
          .z = fbuf[i * feature_number + 2],
      };
      if (feature_number > 3) {
        p.intensity = fbuf[i * feature_number + 3];
      }
      boost::filesystem::path bPath(path);
      p.timestamp = std::strtoull(bPath.filename().stem().c_str(), 0, 0);
      point_cloud.AddPoint(p);
    }
  }
  delete buf;
  buf = nullptr;
  return true;
}

bool DataScene::read_radar_data(
    std::string const& path, std::uint32_t const& feature_number,
    PointCloud<PointXTZDopppler, kMaxPointNum>& point_cloud,
    std::string& err) noexcept {
  if (!is_file_exist(path)) {
    err = "file: " + path + " does not exist";
    return false;
  }

  if (feature_number < kMinradarDataFeatureNum) {
    err = "feature number must be at least " +
          std::to_string(kMinradarDataFeatureNum);
    return false;
  }

  auto binSize{get_binfile_size(path)};
  auto dataNumber{binSize / sizeof(float)};

  // data number is not enough
  if (dataNumber < kMinradarDataFeatureNum) {
    err = "data number: " + std::to_string(dataNumber) + " is not enough";
    return false;
  }

  char* buf{new char[binSize]};
  read_bin_file(path, buf, binSize);
  float* fbuf = reinterpret_cast<float*>(buf);
  auto pointNumber{dataNumber / feature_number};
  point_cloud.Clear();
  for (auto i{0}; i < pointNumber; i++) {
    if (i < kMaxPointNum) {
      PointXTZDopppler p{
          .x = fbuf[i * feature_number + 0],
          .y = fbuf[i * feature_number + 1],
          .z = fbuf[i * feature_number + 2],
      };
      if (feature_number > 3) {
        p.vx = fbuf[i * feature_number + 3];
      }

      if (feature_number > 4) {
        p.vy = fbuf[i * feature_number + 4];
      }

      if (feature_number > 5) {
        p.rcs = fbuf[i * feature_number + 5];
      }

      boost::filesystem::path bPath(path);
      p.timestamp = std::strtoull(bPath.filename().stem().c_str(), 0, 0);
      point_cloud.AddPoint(p);
    }
  }
  delete buf;
  buf = nullptr;
  return true;
}

bool DataScene ::read_calib_data(
    std::string const& path,
    FixedArray<MatrixData, kMaxCalibDataNum>& data_array,
    std::string& err) noexcept {
  boost::system::error_code errorCode;
  if (!boost::filesystem::exists(path, errorCode)) {
    err = "calib data path: " + path +
          "error, directory not exist, error code: " + errorCode.message();
    return false;
  }
  boost::filesystem::directory_iterator pathIter(path);
  for (auto const& file : pathIter) {
    auto& data{data_array.GetNext()};
    data.name = file.path().filename().stem().string();
    if (parse_matrix_data(file.path().string(), data.mat, err)) {
      data.is_valid = true;
    } else {
      data.is_valid = false;
    }
    data_array.Add();
  }
  return true;
}

bool DataScene::parse_matrix_data(std::string const& path, Eigen::MatrixXf& mat,
                                  std::string& err) noexcept {
  if (!is_file_exist(path)) {
    err = "file: " + path + " does not exist";
    return false;
  }

  std::unique_ptr<std::ifstream, std::function<void(std::ifstream*)>> finPtr(
      new std::ifstream(path, std::ifstream::in), [&](std::ifstream* p) {
        if (p != nullptr) p->close();
      });

  std::stringstream buffer;
  buffer << finPtr->rdbuf();

  auto matrixStr{buffer.str()};
  boost::trim(matrixStr);

  std::vector<std::string> matItem;
  boost::split(matItem, matrixStr, boost::is_any_of(" \n\r\0"),
               boost::token_compress_on);

  auto matItemSize{matItem.size()};
  if (matItemSize != 4 && matItemSize != 9 && matItemSize != 16) {
    err = "calibration matrix item number: " + std::to_string(matItemSize) +
          "is illegal";
    return false;
  }

  auto row{static_cast<int>(sqrt(matItemSize))};
  auto col{static_cast<int>(sqrt(matItemSize))};
  mat.resize(row, col);
  for (size_t i = 0; i < matItemSize; i++) {
    auto item{matItem.at(i)};
    long double value{std::stold(item)};
    mat(i / col, i % col) = value;
  }
  return true;
}

void DataScene::load_data_scene(DataScene* const data_scene) noexcept {
  try {
    auto rootPath{data_scene->GetDataPath()};
    boost::system::error_code err;
    if (!boost::filesystem::exists(rootPath, err)) {
      std::cerr << "load data scene: " << rootPath
                << "error, directory not exist, error code: " << err
                << std::endl;
      return;
    }

    // parse data frame information and find calib dir
    DataFrameInfo dataFrameInfoLidar;
    DataFrameInfo dataFrameInfoCamera;
    DataFrameInfo dataFrameInfoRadar;
    DataFrameInfo dataFrameInfoEgo;
    DataFrameInfo dataFrameInfoMapAnno;
    std::string errorMessage;

    std::string syncPathName{"sync_info"};
    std::string calibPathName{"calib"};
    std::string egoPathName{"ego_motion"};
    std::string lidarRootPathName{"lidars"};
    std::string cameraRootPathName{"cameras"};
    std::string radarRootPathName{"radars"};
    std::string mapAnnoRootPathName{"map_anno"};

    auto egoPathRoot{boost::filesystem::complete(egoPathName, rootPath)};
    auto lidarPathRoot{
        boost::filesystem::complete(lidarRootPathName, rootPath)};
    auto cameraPathRoot{
        boost::filesystem::complete(cameraRootPathName, rootPath)};
    auto radarPathRoot{
        boost::filesystem::complete(radarRootPathName, rootPath)};

    auto mapAnnoPathRoot{
        boost::filesystem::complete(mapAnnoRootPathName, rootPath)};

    auto syncInfoPath{boost::filesystem::complete(syncPathName, rootPath)};
    boost::filesystem::directory_iterator syncInfoDirIter(syncInfoPath);

    std::vector<boost::filesystem::path> syncInfoFileList;

    data_scene->travel_timestamp_data_file(syncInfoPath, syncInfoFileList);

    data_scene->frame_number_ = syncInfoFileList.size();
    data_scene->current_frame_index_ = data_scene->frame_number_;

    std::vector<boost::filesystem::path> egoFilePathList;
    std::vector<boost::filesystem::path> mapAnnoFilePathList;

    auto readJson = [](boost::filesystem::path const& path, std::string& out) {
      std::unique_ptr<boost::filesystem::fstream,
                      std::function<void(boost::filesystem::fstream*)>>
          finPtr(new boost::filesystem::fstream(path),
                 [&](boost::filesystem::fstream* p) {
                   if (p != nullptr) p->close();
                 });
      if (!finPtr->is_open()) {
        return;
      }
      std::stringstream s;
      s << finPtr->rdbuf();
      out = s.str();
    };

    for (auto& syncInfoFile : syncInfoFileList) {
      std::string strSync = "";
      readJson(syncInfoFile, strSync);
      boost::json::error_code ec;
      auto jsonDecode = boost::json::parse(strSync, ec);

      if (ec.failed()) {
        std::cout << "[" << to_red("ERROR") << "] " << syncInfoFile
                  << "json decode error" << std::endl;
        continue;
      }

      for (auto& catagory : jsonDecode.as_object()) {
        // lidar
        if (catagory.key() == lidarRootPathName) {
          for (auto& lidar : catagory.value().as_object()) {
            auto name{lidar.key().to_string()};
            auto data{lidar.value().get_int64()};

            auto pathRoot{boost::filesystem::complete(name, lidarPathRoot)};
            auto filePath{boost::filesystem::complete(
                std::to_string(data) + ".bin", pathRoot)};
            if (dataFrameInfoLidar.find(name) != dataFrameInfoLidar.end()) {
              auto& info{dataFrameInfoLidar[name]};
              info.emplace_back(filePath);
            } else {
              std::vector<boost::filesystem::path> pathList;
              pathList.emplace_back(filePath);
              dataFrameInfoLidar.emplace(name, pathList);
            }
          }
        }
        // camera
        if (catagory.key() == cameraRootPathName) {
          for (auto& camera : catagory.value().as_object()) {
            auto name{camera.key().to_string()};
            auto data{camera.value().get_int64()};

            auto pathRoot{boost::filesystem::complete(name, cameraPathRoot)};
            auto filePath{boost::filesystem::complete(
                std::to_string(data) + ".jpg", pathRoot)};
            if (dataFrameInfoCamera.find(name) != dataFrameInfoCamera.end()) {
              auto& info{dataFrameInfoCamera[name]};
              info.emplace_back(filePath);
            } else {
              std::vector<boost::filesystem::path> pathList;
              pathList.emplace_back(filePath);
              dataFrameInfoCamera.emplace(name, pathList);
            }
          }
        }
        // radar
        if (catagory.key() == radarRootPathName) {
          auto radars = catagory.value().as_object();
          for (auto& radar : catagory.value().as_object()) {
            auto name{radar.key().to_string()};
            auto data{radar.value().get_int64()};

            auto pathRoot{boost::filesystem::complete(name, radarPathRoot)};
            auto filePath{boost::filesystem::complete(
                std::to_string(data) + ".bin", pathRoot)};
            if (dataFrameInfoRadar.find(name) != dataFrameInfoRadar.end()) {
              auto& info{dataFrameInfoRadar[name]};
              info.emplace_back(filePath);
            } else {
              std::vector<boost::filesystem::path> pathList;
              pathList.emplace_back(filePath);
              dataFrameInfoRadar.emplace(name, pathList);
            }
          }
        }
      }

      // ego
      auto egoFilePath{boost::filesystem::complete(
          syncInfoFile.filename().stem().string() + ".txt", egoPathRoot)};
      egoFilePathList.emplace_back(egoFilePath);

      // map anno
      auto mapAnnoFilePath{boost::filesystem::complete(syncInfoFile.filename(),
                                                       mapAnnoPathRoot)};
      mapAnnoFilePathList.emplace_back(mapAnnoFilePath);
    }

    dataFrameInfoEgo.emplace("ego", egoFilePathList);

    dataFrameInfoMapAnno.emplace("map_anno", mapAnnoFilePathList);

    auto calibPath{boost::filesystem::complete(calibPathName, rootPath)};
    // load calibration data
    if (!data_scene->read_calib_data(calibPath.string(),
                                     data_scene->calib_data_, errorMessage)) {
      std::cerr << "read calib data: " << calibPath << "error: ";
      std::cerr << errorMessage << '\n';
    }

    while (true) {
      if (data_scene->is_dispose_) {
        return;
      }

      if (data_scene->is_replay_) {
        if (data_scene->current_frame_index_ >= data_scene->frame_number_ - 1) {
          data_scene->current_frame_index_ = 0;
        }
      }

      {
        // std::lock_guard<std::mutex> lock(data_scene->mutex_);
        if (data_scene->data_frame_buffer_.GetNumberFilled() >
            data_scene->data_frame_buffer_.Size() / 2) {
          std::chrono::milliseconds dura(50);
          std::this_thread::sleep_for(dura);
          continue;
        }
      }
      
      {
        // std::lock_guard<std::mutex> lock(data_scene->mutex_);
        if (data_scene->current_frame_index_ >= data_scene->frame_number_ - 1) {
          std::chrono::milliseconds dura(50);
          std::this_thread::sleep_for(dura);
          continue;
        }
      }

      {
        uint64_t currentTimeStamp{0};

        auto& dataFrame{data_scene->data_frame_buffer_.GetNext()};
        std::unique_lock<std::shared_mutex> lock(dataFrame.mutex);
        // read lidar data
        dataFrame.lidar_data.Clear();
        for (auto const& info : dataFrameInfoLidar) {
          if (data_scene->current_frame_index_ < info.second.size()) {
            auto& lidarData{dataFrame.lidar_data.GetNext()};
            lidarData.name = info.first;
            std::string err;
            auto lidarDataPath{
                info.second.at(data_scene->current_frame_index_).string()};
            auto ret{data_scene->read_lidar_data(lidarDataPath, 5,
                                                 lidarData.point_cloud, err)};
            if (ret == true) {
              lidarData.is_valid = true;
            } else {
              lidarData.is_valid = false;
              std::cerr << "read lidar data: " << lidarDataPath << "error: ";
              std::cerr << err << '\n';
            }
            dataFrame.lidar_data.Add();
          }
        }

        // read camera data
        dataFrame.camera_data.Clear();
        for (auto const& info : dataFrameInfoCamera) {
          if (data_scene->current_frame_index_ < info.second.size()) {
            auto& cameraData{dataFrame.camera_data.GetNext()};
            cameraData.name = info.first;
            auto imagePath{info.second.at(data_scene->current_frame_index_)};
            if (is_file_exist(imagePath.string())) {
              cameraData.image_data.image = cv::imread(imagePath.string());
              cameraData.is_valid = true;
            } else {
              cameraData.is_valid = false;
            }
            cameraData.image_data.timestamp =
                std::strtoull(imagePath.filename().stem().c_str(), 0, 0);
            dataFrame.camera_data.Add();
          }
        }

        // read radar data
        dataFrame.radar_data.Clear();
        for (auto const& info : dataFrameInfoRadar) {
          if (data_scene->current_frame_index_ < info.second.size()) {
            auto& radarData{dataFrame.radar_data.GetNext()};
            radarData.name = info.first;
            std::string err;
            auto radarDataPath{
                info.second.at(data_scene->current_frame_index_).string()};
            auto ret{data_scene->read_radar_data(radarDataPath, 6,
                                                 radarData.point_cloud, err)};
            if (ret == true) {
              radarData.is_valid = true;
            } else {
              radarData.is_valid = false;
              std::cerr << "read radar data: " << radarDataPath << "error: ";
              std::cerr << err << '\n';
            }
            dataFrame.radar_data.Add();
          }
        }

        // read ego data
        auto const& egoDataName{"ego"};
        auto const& egoInfo{dataFrameInfoEgo[egoDataName]};
        if (data_scene->current_frame_index_ < egoInfo.size()) {
          auto& egoData{dataFrame.ego_data};
          egoData.name = egoDataName;
          std::string err;
          auto egoDataPath{egoInfo.at(data_scene->current_frame_index_)};
          currentTimeStamp =
              strtoull(egoDataPath.filename().stem().c_str(), 0, 0);
          auto ret{data_scene->parse_matrix_data(egoDataPath.string(),
                                                 egoData.mat, err)};
          if (ret == true) {
            egoData.is_valid = true;
          } else {
            egoData.is_valid = false;
            std::cerr << "read ego data: " << egoDataPath << "error: ";
            std::cerr << err << '\n';
          }
        }

        // read map anno
        for (auto const& info : dataFrameInfoMapAnno) {
          if (data_scene->current_frame_index_ < info.second.size()) {
            auto const& mapAnnoDataPath{
                info.second.at(data_scene->current_frame_index_)};
            if (is_file_exist(mapAnnoDataPath.string())) {
              std::string strMapAnno;
              readJson(mapAnnoDataPath, strMapAnno);
              boost::json::error_code ec;
              auto jsonDecode = boost::json::parse(strMapAnno, ec);

              if (ec.failed()) {
                std::cout << "[" << to_red("ERROR") << "] " << mapAnnoDataPath
                          << "json decode error" << std::endl;
                continue;
              }

              dataFrame.map_anno.timestamp =
                  strtoul(mapAnnoDataPath.filename().stem().c_str(), 0, 0);

              for (auto const& catagory : jsonDecode.as_object()) {
                auto const& catagoryName = catagory.key().to_string();

                if (!catagory.value().is_array()) {
                  continue;
                }

                if (catagoryName != "lane_divider") {
                  dataFrame.map_anno.lane_divider.Clear();
                  for (auto const& lv : catagory.value().as_array()) {
                    auto& laneMarkerLine{
                        dataFrame.map_anno.lane_divider.GetNext()};
                    for (auto const& lines : lv.as_object()) {
                      auto const& propertyName = lines.key().to_string();
                      if (propertyName == "id") {
                        laneMarkerLine.id = lines.value().get_string().c_str();
                      }
                      if (propertyName == "line_type") {
                        auto const& lineTypeName = lines.value().get_string();
                        if (lineTypeName == "dashed") {
                          laneMarkerLine.type = LineType::Dashed;
                        }
                        if (lineTypeName == "solid") {
                          laneMarkerLine.type = LineType::Solid;
                        }
                      }
                      if (propertyName == "color") {
                        laneMarkerLine.color =
                            lines.value().get_string().c_str();
                      }

                      if (propertyName == "points") {
                        if (!lines.value().is_array()) {
                          continue;
                        }

                        laneMarkerLine.points.Clear();
                        for (auto const& pv : lines.value().as_array()) {
                          if (!pv.is_array()) {
                            continue;
                          }
                          auto& point{laneMarkerLine.points.GetNext()};
                          auto const& data = pv.get_array();
                          if (data.size() > 0) {
                            point.x = data.at(0).get_double();
                          }
                          if (data.size() > 1) {
                            point.y = data.at(1).get_double();
                          }
                          if (data.size() > 2) {
                            point.z = data.at(2).get_double();
                          }
                          laneMarkerLine.points.Add();
                        }
                      }
                    }
                    dataFrame.map_anno.lane_divider.Add();
                  }
                }
                if (catagoryName != "road_edge") {
                  // to do
                }

                if (catagoryName != "road_marking") {
                  // to do
                }
              }
            }
          }
        }

        dataFrame.timestamp = currentTimeStamp;
      }

      {
        std::lock_guard<std::mutex> lock(data_scene->mutex_);
        data_scene->data_frame_buffer_.Push();
        data_scene->current_frame_index_++;
      }
    }
  } catch (const std::exception& e) {
    std::cerr << "load data scene " << data_scene->data_path_ << "error: ";
    std::cerr << e.what() << '\n';
  } catch (...) {
    std::cerr << "load data scene: " << data_scene->data_path_
              << "unexpected error!!!" << std::endl;
  }
}